﻿using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.ComponentModel.Design.Serialization;
using System.Diagnostics;
using Microsoft.WowAddonStudio.FrameXml.Components;
using Microsoft.WowAddonStudio.FrameXml.Components.Support;
using Microsoft.WowAddonStudio.FrameXml.Design.Services.NameCreationService;
using Microsoft.WowAddonStudio.FrameXml.Serialization;

namespace Microsoft.WowAddonStudio.FrameXml.Design.Support
{
	public class LoaderHostComponentActivator : IComponentActivator, IDisposable
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="LoaderHostComponentActivator"/> class.
		/// </summary>
		/// <param name="loaderHost">The loader host.</param>
		public LoaderHostComponentActivator(IDesignerLoaderHost loaderHost)
		{
			if (loaderHost == null)
				throw new ArgumentNullException("loaderHost");

			LoaderHost = loaderHost;

			//Create new instance of NameCreationService
			NameCreationService = new FrameXmlNameCreationService(loaderHost);

			//Add NameCreationService to the container
			LoaderHost.AddService(typeof (INameCreationService), NameCreationService);

			//Gets IComponentChangeService instance from container
			ComponentChangeService = LoaderHost.GetService(typeof (IComponentChangeService)) as IComponentChangeService;

			//add listener to the ComponentAdding event
			if (ComponentChangeService != null)
			{
				ComponentChangeService.ComponentAdding += OnComponentAdding;
			}
		}

		/// <summary>
		/// Gets or sets the loader host.
		/// </summary>
		/// <value>The loader host.</value>
		protected IDesignerLoaderHost LoaderHost { get; private set; }

		/// <summary>
		/// Gets or sets the component change service.
		/// </summary>
		/// <value>The component change service.</value>
		protected IComponentChangeService ComponentChangeService { get; private set; }

		/// <summary>
		/// Gets or sets the name creation service.
		/// </summary>
		/// <value>The name creation service.</value>
		protected INameCreationService NameCreationService { get; private set; }

		/// <summary>
		/// Creates a component.
		/// </summary>
		/// <param name="componentClass">The type of the component.</param>
		/// <returns>The newly created component.</returns>
		public object CreateComponent(Type componentClass)
		{
			return LoaderHost.CreateComponent(componentClass);
		}

		/// <summary>
		/// Called when [component adding].
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="System.ComponentModel.Design.ComponentEventArgs"/> instance containing the event data.</param>
		private void OnComponentAdding(object sender, ComponentEventArgs e)
		{
			if (e.Component != null)
			{
				Type dataType = null;
				InheritableObject layoutFrame;
				IFrameXmlComponent newControl = e.Component as LayoutFrameControl;

				if (newControl != null && string.IsNullOrEmpty(newControl.Name))
				{
					layoutFrame = newControl.SerializationObject as InheritableObject;

					if (layoutFrame != null)
						dataType = layoutFrame.GetType();
				}
				else
				{
					newControl = e.Component as IFrameXmlComponent;

					if (newControl != null && string.IsNullOrEmpty(newControl.Name))
						dataType = newControl.SerializationObject.GetType();
				}
				
                if (newControl != null && dataType != null)
				{
					layoutFrame = newControl.SerializationObject as InheritableObject;
					string newName = CreateName(dataType);

					Debug.WriteLine("Generated name: "+ newName);
					if (newControl.Site != null)
					{
						newControl.Name = newName;
					}
					if (layoutFrame != null)
					{
						layoutFrame.Name = newName;
					}
				}
			}
		}

		/// <summary>
		/// Gets the name.
		/// </summary>
		/// <param name="dataType">Type of the data.</param>
		/// <returns></returns>
		private string CreateName(Type dataType)
		{
			var container = LoaderHost.GetService(typeof (IContainer)) as IContainer;

			if (container == null)
				throw new MissingServiceException(Resources.IContainerIsNotAvailableMessage);

			return NameCreationService.CreateName(container, dataType);
		}

		#region IDisposable Members

		/// <summary>
		/// Performs application-defined tasks associated with freeing,
		/// releasing, or resetting unmanaged resources.
		/// </summary>
		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		/// <summary>
		/// Performs application-defined tasks associated with freeing,
		/// releasing, or resetting unmanaged resources.
		/// </summary>
		protected virtual void Dispose(bool disposing)
		{
			if (ComponentChangeService != null)
				ComponentChangeService.ComponentAdding -= OnComponentAdding;
		}

		#endregion
	}
}